#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
#define gcap 5

template <class Task>
class ring_queue
{
    void P(sem_t & sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t & sem)
    {
        sem_post(&sem);
    }

public:
    ring_queue(int cap = gcap)
        : _cap(cap), _p_index(0), _c_index(0)
    {
        _qt.resize(_cap);
        sem_init(&_space_sem, 0, 5);
        sem_init(&_resource_sem, 0, 0);
        pthread_mutex_init(&_p_mtx, nullptr);
        pthread_mutex_init(&_c_mtx, nullptr);
    }

    void push(const Task &task)
    {
        // 申请队列空间
        P(_space_sem);
        pthread_mutex_lock(&_p_mtx);
        _qt[_p_index++] = task;
        _p_index %= _cap;
        pthread_mutex_unlock(&_p_mtx);
        // 增加资源
        V(_resource_sem);
    }

    void pop(Task * task)
    {
        // 获取资源
        P(_resource_sem);
        pthread_mutex_lock(&_c_mtx);
        *task = _qt[_c_index++];
        _c_index %= _cap;
        pthread_mutex_unlock(&_c_mtx);
        // 归还队列空间
        V(_space_sem);
    }

    ~ring_queue()
    {
        sem_destroy(&_space_sem);
        sem_destroy(&_resource_sem);
        pthread_mutex_destroy(&_p_mtx);
        pthread_mutex_destroy(&_c_mtx);
    }

private:
    std::vector<Task> _qt;
    int _cap;
    int _p_index;
    int _c_index;
    sem_t _space_sem;
    sem_t _resource_sem;
    pthread_mutex_t _p_mtx;
    pthread_mutex_t _c_mtx;
};